package com.jdd.modules.sdk.sdkidentifycallbackresults;

import com.jdd.common.constant.JddConstant;
import com.jdd.common.util.AsynRestTmplateUtils;
import com.jdd.common.util.CacheUtil;
import com.jdd.common.util.OssUtil;
import com.jdd.common.util.SnowFlakeUtil;
import com.jdd.modules.parking.entity.ParkArmInfo;
import com.jdd.modules.parking.service.IParkArmInfoService;
import com.jdd.modules.sdk.utils.CheckSystemUtil;
import com.jdd.modules.sdk.utils.IPlateCallback;
import com.jdd.modules.sdkidentifyresultpushlog.entity.SdkIdentifyResultPushLog;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogService;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogV3Service;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.util.*;

/**
 * @author ：jdd孙庆伟
 * @date ：Created in 2021/7/26 16:15
 * @description：华夏相机识别回调
 * @modified By：`
 * @version: 1.0
 */
@Slf4j
@Component
public class HuaXiaSdkIdentifyCallbackResults implements IPlateCallback {
    @Resource
    private ISdkIdentifyResultPushLogService sdkIdentifyResultPushLogService;
    @Resource
    private IParkArmInfoService parkArmInfoService;
    @Value("${uploadImages.location}")
    private String imageLocation;
    @Value("${uploadFile.location}")
    private String location;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private OssUtil ossUtil;

    public String appScrect;

    public String appId;
    @Resource
    private ISdkIdentifyResultPushLogV3Service sdkIdentifyResultPushLogV3Service;
    @Resource
    AsynRestTmplateUtils asynRestTmplateUtils;
    @Value("${oss.domain.name}")
    private String ossDomainName;
    @Override
    public void callback(Pointer pvParam, String pcIP, String pcNumber, String pcColor, Pointer pvPicData, NativeLong nPicLen,
                         Pointer pvPlatePicData, NativeLong nPlatePicLen, NativeLong nPlatePosLeft, NativeLong nPlatePosTop, NativeLong nPlatePosRight,
                         NativeLong nPlatePosBottom, float fPlateConfidence, NativeLong nVehicleColor, NativeLong nPlateType, NativeLong nVehicleDir,
                         NativeLong nAlarmType, NativeLong nSpeed, NativeLong nCapTime, NativeLong nVehicleType, NativeLong nResultHigh, NativeLong nResultLow) {
        try {
            //通过ip拿到闸机序列号，然后会通过序列号拿到拿到场端code
            ParkArmInfo parkArmInfo = parkArmInfoService.findParkArmInfoByIp(pcIP);
            if (null == parkArmInfo) {
                return;
            }

            //linux的需要从方法拿，如果是Windows直接可用
            if (CheckSystemUtil.checkSystem().equals(JddConstant.SystemType.LINUX_SYSTEM)) {
                Map<String, String> plateAndColorMap = getPlateAndColorFromLinux(nResultHigh, nResultLow);
                pcColor = plateAndColorMap.get("color");
                pcNumber = plateAndColorMap.get("plate");
            }
//
//            String property = System.getProperty("sun.jnu.encoding");
//            byte[] bytes = pcNumber.getBytes(property);
//            pcNumber = new String(bytes, "GB2312");

            //组装识别信息
            SdkIdentifyResultPushLog sdkIdentifyResultPushLog = new SdkIdentifyResultPushLog();
            sdkIdentifyResultPushLog.setId(SnowFlakeUtil.getId());
            sdkIdentifyResultPushLog.setIpAddr(pcIP);
            sdkIdentifyResultPushLog.setParkCode(parkArmInfo.getParkCode());
            sdkIdentifyResultPushLog.setParkName(parkArmInfo.getParkName());
            sdkIdentifyResultPushLog.setSerialNo(parkArmInfo.getSerialNo());
            sdkIdentifyResultPushLog.setCreateTime(new Date());
            sdkIdentifyResultPushLog.setLicense(pcNumber);
            sdkIdentifyResultPushLog.setNTime(nCapTime.intValue());
            sdkIdentifyResultPushLog.setNType(nType.getTypeCode(nPlateType.intValue()).getValue());
            sdkIdentifyResultPushLog.setColor(nVehicleColor.intValue());
            sdkIdentifyResultPushLog.setNDirection(nVehicleDir.intValue());
            sdkIdentifyResultPushLog.setNColor(getNColor(pcColor));
            //识别信息设置图片数据
            mkdirsAndSavePic(sdkIdentifyResultPushLog, pvPicData, nPicLen);
            //保存数据
            sdkIdentifyResultPushLogService.save(sdkIdentifyResultPushLog);
            // 第三版出入场逻辑调用
            sdkIdentifyResultPushLogV3Service.identifyJudge(sdkIdentifyResultPushLog, parkArmInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存图片
     *
     * @author lcy
     */
    public static void savePic(String filename, byte[] data) {
        try {
            DataOutputStream out = new DataOutputStream(new FileOutputStream(filename));
            out.write(data);
            out.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 获得颜色序号
     *
     * @param strColor
     * @return java.lang.Integer
     * @author jdd孙庆伟
     * @date 2021/7/28 10:37:38
     * @version 1.0
     */
    public Integer getNColor(String strColor) {
        int color = -1;
        switch (strColor) {
            case "蓝色":
                color = 1;
                break;
            case "黄色":
                color = 2;
                break;
            case "白色":
                color = 3;
                break;
            case "黑色":
                color = 4;
                break;
            case "绿色":
                color = 5;
                break;
            default:
                break;
        }
        return color;
    }

    public enum nType {
        //未知车牌
        UNKNOWN(0, 0),
        //蓝牌小汽车"
        BLUE(1, 1),
        //"单排黄牌
        SGINLEYELLOW(2, 3),
        //双排黄牌
        DOUBLEYELLOW(16, 4),
        //警车车牌
        POLICE(4, 5),
        //武警车牌
        ARMEDPOLICE(8, 6),
        //个性化车牌
        SPECIAL(256, 7),
        //单排军车牌
        SGINLEARMY(128, 8),
        //双排军车牌
        DOUBLEARMY(128, 9),
        //使馆车牌
        EMBASSY(1024, 10),
        //香港进出中国大陆车牌
        HK(512, 11),
        //农用车牌
        ARGICULTURE(6552, 12),
        //教练车牌
        TRAIN(64, 13),
        //澳门进出中国大陆车牌
        MACAO(512, 14),
        //双层武警车牌
        DBARMEDPOLICE(8, 15),
        //武警总队车牌
        GENELARMEDPOLICE(8, 16),
        //双层武警总队车牌
        DBGENELARMEDPOLICE(8, 17),
        //民航车牌
        CIVIL(4096, 18),
        //新能源车牌
        ENERGY(8192, 19),
        //新能源车牌大车
        NEWENERGYBIG(16384, 19),
        //应急车
        EMERGENCY(3276, 1),
        //摩托车
        MOTOR(32, 1);


        private final Integer key;
        private final Integer value;

        private nType(Integer key, Integer value) {
            this.key = key;
            this.value = value;
        }

        public Integer getKey() {
            return key;
        }

        public Integer getValue() {
            return value;
        }

        public static nType getTypeCode(Integer key) {
            //stream使用findAny取得是第一个值
            //parallelStream使用findAny是随机
            return Arrays.asList(nType.values()).stream()
                    .filter(alarmGrade -> alarmGrade.getKey().equals(key))
                    .findAny().orElse(nType.UNKNOWN);
        }
    }

    /**
     * linux环境转换NativeLong成为字符串类型工具
     *
     * @param data
     * @param offset
     * @param len
     * @return
     */
    private static int strlen(byte[] data, int offset, int len) {
        for (int i = 0; i < len; i++) {
            if (data[offset + i] == '\0') {
                return i;
            }
        }
        return len;
    }

    /**
     * linux环境拿到车牌
     *
     * @param nResultHigh
     * @param nResultLow
     * @return
     */
    private Map<String, String> getPlateAndColorFromLinux(NativeLong nResultHigh, NativeLong nResultLow) {
        //Linux环境
        Map<String, String> map = new HashMap<>(2);
        String plateNo = null;
        String color = null;
        if (nResultLow.intValue() != 0) {
            //获取车牌结构体指针
            long peer = ((long) nResultHigh.intValue() << 32) + nResultLow.intValue();
            Pointer ptr = new Pointer(peer);
            //车牌号
            byte[] szPlateNum = ptr.getByteArray(368, 16);
            int PlateNumLen = strlen(szPlateNum, 0, 16);
            try {
                plateNo = new String(szPlateNum, 0, PlateNumLen, "GB2312");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            //车牌颜色
            byte[] szPlateColor = ptr.getByteArray(332, 32);
            int ColorLen = strlen(szPlateColor, 0, 32);
            try {
                color = new String(szPlateColor, 0, ColorLen, "GB2312");
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info("number:" + plateNo + "," + color);
            map.put("plate", plateNo);
            map.put("color", color);
        }
        return map;
    }

    /**
     * 创建保存图片的文件夹并且保存图片
     *
     * @param sdkIdentifyResultPushLog
     * @param pvPicData
     * @param nPicLen
     */
    private void mkdirsAndSavePic(SdkIdentifyResultPushLog sdkIdentifyResultPushLog, Pointer pvPicData, NativeLong nPicLen) {
        //oss图片路径
        String ossImg = null;
        //本地图片路径
        String urls = null;
        //如果存在图片
        if (nPicLen.intValue() > 0) {
            /* 保存抓拍图片*/
            Random random = new Random();
            String result = "";
            byte[] dst = new byte[nPicLen.intValue()];
            pvPicData.read(0, dst, 0, nPicLen.intValue());
            //随机生成6位随机数
            for (int i = 0; i < 6; i++) {
                result += random.nextInt(10);
            }
//            //抓拍时间,每天一个文件夹
            Calendar instance = Calendar.getInstance();
            int year = instance.get(Calendar.YEAR);
            int month = instance.get(Calendar.MONTH) + 1;
            int day = instance.get(Calendar.DAY_OF_MONTH);
            //创建文件夹
            //文件夹名字生成规则请勿轻易更改，如果更改，请修改定时删除图片任务的文件夹名字的生成规则
            String imgUrl = imageLocation + "/" + year + "-" + month + "-" + day;
            File dir = new File(imgUrl);
            //判断目录是否存在不存在则新建
            if (!dir.exists()) {
                try {
                    dir.mkdirs();
                } catch (Exception e) {
                    log.error("新建图片文件夹失败->{}", e);
                }
            }

            long timeMillis = System.currentTimeMillis();
            //图片存放路径
            //文件夹名字生成规则请勿轻易更改，如果更改，请修改定时删除图片任务的文件夹名字的生成规则
            String impart = imgUrl + File.separator + timeMillis + result + ".jpeg";
            //图片保存本地并返回
            savePic(impart, dst);//存全景图

            urls = location + "/" + year + "-" + month + "-" + day + File.separator  + timeMillis + result + ".jpeg";

            sdkIdentifyResultPushLog.setImg(urls);

            String getOssUrl = ossUtil.getImgUrl();

            sdkIdentifyResultPushLog.setOssImg(ossDomainName+getOssUrl);

            asynRestTmplateUtils.uploadOssImg(impart,getOssUrl);



        }
    }
}
